package cgs_worksheet

import (
	"cgs-server/server"
	"cgs-server/server/base"
	"cgs-server/server/model"
	"cgs-server/server/system"
	"errors"
	"go.mongodb.org/mongo-driver/bson"
	"go.mongodb.org/mongo-driver/bson/primitive"
	"go.mongodb.org/mongo-driver/mongo/options"
)

type WorksheetRepository interface {
	base.Repository
	// 根据visualId 查询所有表单信息
	FindByVisualId(visualId string, user *system.User) ([]*WorksheetInfo, error)
	// 根据表单 ids 查询
	FindByFormIds(ids []primitive.ObjectID) ([]*WorksheetInfo, error)
	// 查询表单数据
	FindFormData(collectionName string) (*bson.A, error)
	// 新增表单信息
	AddWorksheet(wsInfo *WorksheetInfo) error
	// 批量新增表单数据
	BatchAddFormData(collectionName string, doc *bson.A) error
	// 新增一条表单数据
	AddOneFormData(mdl *model.DataUserModel) error
	// api 接口批量新增表单数据
	BatchAddRow(mdl *model.DataUserModel) error
	// 更新一条表单数据
	UpdateOneFormData(mdl *model.DataUserModel) error
	// 更新一条表单数据
	UpdateFormDataBatch(mdl *model.DataUserModel) error
	// 逻辑删除一条表单数据
	DeleteOneFormDataLogic(mdl *model.DataUserModel) error
	// 批量删除表单数据
	BatchDeleteFormDataLogic(mdl *model.DataUserModel) error
	// 从Excel导入数据
	ImportExcelData(mdl *model.DataUserModel) error
	// 查询某个表格记录数
	CountRows(collectionName string, filter *bson.M) (int64, error)

	// 根据过滤条件查询表单数据
	FindFilterFormData(mdl *model.DataUserModel) (interface{}, error)
	// 查询行记录详情
	GetRowById(mdl *model.DataUserModel) (interface{}, error)

	ClearData(collectionName string) error
}

func NewWorksheetRepository() WorksheetRepository {
	return &worksheetRepository{
		base.RepositoryStruct{
			CollectionName: server.CgsWorksheetInfoCollectionName,
		},
	}
}

type worksheetRepository struct {
	base.RepositoryStruct
}

func (w *worksheetRepository) ClearData(collectionName string) error {
	if err := w.CheckDB(); err != nil {
		return err
	}

	return w.Mongo.DropCollection(collectionName)
}

func (w *worksheetRepository) FindByFormIds(ids []primitive.ObjectID) ([]*WorksheetInfo, error) {
	if err := w.CheckDB(); err != nil {
		return nil, err
	}
	filter := bson.M{
		"id": bson.M{
			"$in": ids,
		},
	}
	filter1 := bson.M{
		"$or": bson.A{
			bson.M{
				"isDeleted": 0,
			},
			bson.M{
				"isDeleted": nil,
			},
		},
	}
	filter = bson.M{
		"$and": bson.A{
			filter,
			filter1,
		},
	}
	var result = []*WorksheetInfo{}
	err := w.Mongo.FindMany(w.CollectionName, filter, &result)
	return result, err
}

func (w *worksheetRepository) BatchAddRow(mdl *model.DataUserModel) error {
	if batchAddRowVo, ok := mdl.Data.(*BatchAddRowVo); ok {
		if err := w.CheckDB(); err != nil {
			return err
		}
		if batchAddRowVo.WsInfo == nil || batchAddRowVo.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}

		list := batchAddRowVo.GetWsRowDataList()
		doc := bson.A{}
		for _, rowData := range list {
			_ = rowData.TransferData()
			rowData.ResolveEntity(rowData, mdl.User)
			doc = append(doc, rowData)
		}
		if len(doc) == 0 {
			return nil
		}
		_, err := w.Mongo.InsertMany(batchAddRowVo.WsInfo.WsCollection, doc)
		return err
	} else {
		return errors.New("WsRowDataVo type error")
	}
}

func (w *worksheetRepository) ImportExcelData(mdl *model.DataUserModel) error {
	if importExcelVo, ok := mdl.Data.(*ImportExcelVo); ok {
		if err := w.CheckDB(); err != nil {
			return err
		}
		if importExcelVo.WsInfo == nil || importExcelVo.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}
		if importExcelVo.RowList == nil || len(importExcelVo.RowList) == 0 {
			return errors.New("Excel data is empty")
		}
		doc := bson.A{}
		for _, rowData := range importExcelVo.RowList {
			rowData.ResolveEntity(rowData, mdl.User)
			doc = append(doc, rowData)
		}
		_, err := w.Mongo.InsertMany(importExcelVo.WsInfo.WsCollection, doc)
		return err
	} else {
		return errors.New("WsRowData type error")
	}
}

func (w *worksheetRepository) BatchDeleteFormDataLogic(mdl *model.DataUserModel) error {
	if batchDeleteRowVo, ok := mdl.Data.(*BatchDeleteRowVo); ok {
		if batchDeleteRowVo.WsInfo == nil || batchDeleteRowVo.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}
		//wsRowData.wsIfo.WsCollection  数据库表使用这个
		if err := w.CheckDB(); err != nil {
			return err
		}
		ids := bson.A{}
		for _, id := range batchDeleteRowVo.RowIds {
			bsonId, err := primitive.ObjectIDFromHex(id)
			if err == nil {
				ids = append(ids, bsonId)
			}
			ids = append(ids, id)
		}
		filter := bson.M{
			"rowId": bson.M{
				"$in": ids,
			},
		}
		// 删除全部
		if batchDeleteRowVo.IsAll {
			filter = bson.M{}
		}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		batchDeleteRowVo.ResolveFilter(batchDeleteRowVo, mdl.User, &filter)
		set := bson.M{}
		batchDeleteRowVo.DeleteLogic(batchDeleteRowVo, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := w.Mongo.UpdateMany(batchDeleteRowVo.WsInfo.WsCollection, filter, update)
		return err
	} else {
		return errors.New("BatchDeleteRowVo type error")
	}
}

func (w *worksheetRepository) DeleteOneFormDataLogic(mdl *model.DataUserModel) error {
	if wsRowData, ok := mdl.Data.(*WsRowData); ok {
		if wsRowData.WsInfo == nil || wsRowData.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}
		//wsRowData.wsIfo.WsCollection  数据库表使用这个
		if err := w.CheckDB(); err != nil {
			return err
		}
		filter := checkRowId(wsRowData.RowId)
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		wsRowData.ResolveFilter(wsRowData, mdl.User, &filter)
		set := bson.M{}
		wsRowData.DeleteLogic(wsRowData, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := w.Mongo.UpdateOne(wsRowData.WsInfo.WsCollection, filter, update)
		return err
	} else {
		return errors.New("WsRowData type error")
	}
}

func (w *worksheetRepository) UpdateOneFormData(mdl *model.DataUserModel) error {
	if wsRowData, ok := mdl.Data.(*WsRowData); ok {
		if wsRowData.WsInfo == nil || wsRowData.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}
		//wsRowData.wsIfo.WsCollection  数据库表使用这个
		if err := w.CheckDB(); err != nil {
			return err
		}
		filter := checkRowId(wsRowData.RowId)
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		wsRowData.ResolveFilter(wsRowData, mdl.User, &filter)
		set := bson.M(wsRowData.RowData)
		wsRowData.ResolveUpdateCondition(wsRowData, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		updateResult, err := w.Mongo.UpdateOne(wsRowData.WsInfo.WsCollection, filter, update)
		if updateResult.MatchedCount == 0 {
			return errors.New("no data matched with rowId: " + wsRowData.RowId)
		}
		return err
	} else {
		return errors.New("WsRowData type error")
	}
}

func (w *worksheetRepository) UpdateFormDataBatch(mdl *model.DataUserModel) error {
	if wsRowData, ok := mdl.Data.(*WsRowDataBatch); ok {
		if wsRowData.WsInfo == nil || wsRowData.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}
		//wsRowData.wsIfo.WsCollection  数据库表使用这个
		if err := w.CheckDB(); err != nil {
			return err
		}
		ids := bson.A{}
		for _, id := range wsRowData.RowIds {
			bsonId, err := primitive.ObjectIDFromHex(id)
			if err == nil {
				ids = append(ids, bsonId)
			}
			ids = append(ids, id)
		}
		filter := bson.M{
			"rowId": bson.M{
				"$in": ids,
			},
		}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		wsRowData.ResolveFilter(wsRowData, mdl.User, &filter)
		set := bson.M(wsRowData.RowData)
		wsRowData.ResolveUpdateCondition(wsRowData, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := w.Mongo.UpdateMany(wsRowData.WsInfo.WsCollection, filter, update)
		return err
	} else {
		return errors.New("WsRowDataBatch type error")
	}
}

func (w *worksheetRepository) FindByVisualId(visualId string, user *system.User) ([]*WorksheetInfo, error) {
	if err := w.CheckDB(); err != nil {
		return nil, err
	}
	filter := bson.M{
		//"userId": user.ID,
		"visualData": visualId,
	}
	filter1 := bson.M{
		"$or": bson.A{
			bson.M{
				"isDeleted": 0,
			},
			bson.M{
				"isDeleted": nil,
			},
		},
	}
	filter = bson.M{
		"$and": bson.A{
			filter,
			filter1,
		},
	}
	var result []*WorksheetInfo
	err := w.Mongo.FindMany(w.CollectionName, filter, &result)
	return result, err
}

func (w *worksheetRepository) FindFormData(collectionName string) (*bson.A, error) {
	if collectionName == "" {
		return nil, errors.New("CollectionName is required.")
	}
	filter := bson.M{
		"$or": bson.A{
			bson.M{
				"isDeleted": 0,
			},
			bson.M{
				"isDeleted": nil,
			},
		},
	}

	// excel 支持的最大行数
	limit := int64(1048576)
	opts := options.FindOptions{
		Limit: &limit,
		Projection: bson.M{
			"isDeleted": 0,
			"_id":       0,
		},
		//Sort: bson.M{
		//	"updateTime": -1,
		//},
	}
	result := &bson.A{}
	err := w.Mongo.FindMany(collectionName, filter, result, &opts)
	if err != nil {
		return nil, err
	}
	return result, nil
}

func (w *worksheetRepository) AddWorksheet(wsInfo *WorksheetInfo) error {
	if err := w.CheckDB(); err != nil {
		return err
	}
	_, err := w.Mongo.InsertOne(w.CollectionName, wsInfo)
	return err
}

func (w *worksheetRepository) BatchAddFormData(collectionName string, doc *bson.A) error {
	if err := w.InitDB(); err != nil {
		return err
	}
	_, err := w.Mongo.InsertMany(collectionName, *doc)
	return err
}

// 查询表单列表
func (w *worksheetRepository) Find(mdl *model.DataUserModel) (interface{}, error) {
	if wsInfo, ok := mdl.Data.(*WorksheetInfo); ok {
		if err := w.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		wsInfo.ResolveFilter(wsInfo, mdl.User, &filter)
		findOptions := options.FindOptions{}
		if mdl.Options != nil {
			findOptions = *mdl.Options
		}
		var err error
		if mdl.Simplify {
			var result = []*WorksheetInfoVo{}
			err = w.Mongo.FindMany(w.CollectionName, filter, &result, &findOptions)
			if err != nil {
				return nil, err
			}
			return result, nil
		} else {
			var result = []*WorksheetInfo{}
			err = w.Mongo.FindMany(w.CollectionName, filter, &result, &findOptions)
			if err != nil {
				return nil, err
			}
			return result, nil
		}
	} else {
		return nil, errors.New("WorksheetInfo type error")
	}
}

/*func (w *worksheetRepository) Count(mdl *model.DataUserModel) (int64, error) {
	if err := w.CheckDB(); err != nil {
		return 0, err
	}
	filter := bson.M{}
	if mdl.Filter != nil {
		filter = *mdl.Filter
	}
	return w.Mongo.Count(w.CollectionName, filter)
}*/

// 添加表单
func (w *worksheetRepository) Insert(mdl *model.DataUserModel) error {
	if wsInfo, ok := mdl.Data.(*WorksheetInfo); ok {
		if err := w.CheckDB(); err != nil {
			return err
		}
		wsInfo.ResolveEntity(wsInfo, mdl.User)
		_, err := w.Mongo.InsertOne(w.CollectionName, wsInfo)
		return err
	} else {
		return errors.New("WorksheetInfo type error")
	}
}

// 修改表单
func (w *worksheetRepository) Update(mdl *model.DataUserModel) error {
	if wsInfo, ok := mdl.Data.(*WorksheetInfo); ok {
		if err := w.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"id": wsInfo.Id,
		}
		wsInfo.ResolveFilter(wsInfo, mdl.User, &filter)
		set := bson.M{}
		if wsInfo.WsName != "" {
			set["wsName"] = wsInfo.WsName
		}
		if len(wsInfo.VisualData) > 0 {
			set["visualData"] = wsInfo.VisualData
		}
		if wsInfo.Config != "" {
			set["config"] = wsInfo.Config
		}
		if len(wsInfo.Fields) > 0 {
			set["fields"] = wsInfo.Fields
		}
		wsInfo.ResolveUpdateCondition(wsInfo, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := w.Mongo.UpdateOne(w.CollectionName, filter, update)
		return err
	} else {
		return errors.New("WorksheetInfo type error")
	}
}

// 逻辑删除表单
func (w *worksheetRepository) DeleteLogic(mdl *model.DataUserModel) error {
	if wsInfo, ok := mdl.Data.(*WorksheetInfo); ok {
		if err := w.CheckDB(); err != nil {
			return err
		}
		filter := bson.M{
			"id": wsInfo.Id,
		}
		wsInfo.ResolveFilter(wsInfo, mdl.User, &filter)
		set := bson.M{}
		wsInfo.DeleteLogic(wsInfo, mdl.User, &set)
		update := bson.M{
			"$set": set,
		}
		_, err := w.Mongo.UpdateOne(w.CollectionName, filter, update)
		return err
	} else {
		return errors.New("WorksheetInfo type error")
	}
}

// 查询单个表单
func (w *worksheetRepository) FindOne(mdl *model.DataUserModel) (interface{}, error) {
	if wsInfo, ok := mdl.Data.(*WorksheetInfo); ok {
		if err := w.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{
			"id": wsInfo.Id,
		}
		wsInfo.ResolveFilter(wsInfo, mdl.User, &filter)
		findOptions := options.FindOneOptions{}
		if mdl.FindOneOptions != nil {
			findOptions = *mdl.FindOneOptions
		}
		result := &WorksheetInfo{}
		find, err := w.Mongo.FindOne(w.CollectionName, filter, result, &findOptions)
		if err != nil {
			return nil, err
		}
		if !find {
			return nil, errors.New("worksheet not found")
		}
		return result, nil
	} else {
		return nil, errors.New("WorksheetInfo type error")
	}
}

// 添加一条表单数据
func (w *worksheetRepository) AddOneFormData(mdl *model.DataUserModel) error {
	if wsRowData, ok := mdl.Data.(*WsRowData); ok {
		if err := w.CheckDB(); err != nil {
			return err
		}
		if wsRowData.WsInfo == nil || wsRowData.WsInfo.WsCollection == "" {
			return errors.New("worksheetInfo is nil or wsCollection is empty")
		}
		//wsRowData.wsIfo.WsCollection  数据库表使用这个
		wsRowData.ResolveEntity(wsRowData, mdl.User)
		_, err := w.Mongo.InsertOne(wsRowData.WsInfo.WsCollection, wsRowData)
		return err
	} else {
		return errors.New("WsRowData type error")
	}
}

func (w *worksheetRepository) CountRows(collectionName string, filter *bson.M) (int64, error) {
	if err := w.CheckDB(); err != nil {
		return 0, err
	}
	if collectionName == "" {
		return 0, errors.New("collectionName is empty")
	}
	if filter == nil {
		filter = &bson.M{}
	}
	return w.Mongo.Count(collectionName, filter)
}

func (w *worksheetRepository) FindFilterFormData(mdl *model.DataUserModel) (interface{}, error) {
	if filterParam, ok := mdl.Data.(*FilterParam); ok {
		if err := w.CheckDB(); err != nil {
			return nil, err
		}
		filter := bson.M{}
		if mdl.Filter != nil {
			filter = *mdl.Filter
		}
		filterParam.ResolveFilter(filterParam, mdl.User, &filter)
		opts := options.Find()
		if mdl.Options != nil {
			opts = mdl.Options
		}
		doc := bson.A{}
		err := w.Mongo.FindMany(filterParam.WsCollection, filter, &doc, opts)
		if err != nil {
			return nil, err
		}
		return doc, nil
	} else {
		return nil, model.NewTypeError("filterParam")
	}
}

func (w *worksheetRepository) GetRowById(mdl *model.DataUserModel) (interface{}, error) {
	if wsRowData, ok := mdl.Data.(*WsRowData); ok {
		if err := w.CheckDB(); err != nil {
			return nil, err
		}
		filter := checkRowId(wsRowData.RowId)
		wsRowData.ResolveFilter(wsRowData, mdl.User, &filter)
		opts := options.FindOne()
		if mdl.FindOneOptions != nil {
			opts = mdl.FindOneOptions
		}
		result := &bson.M{}
		find, err := w.Mongo.FindOne(wsRowData.WsInfo.WsCollection, filter, result, opts)
		if find {
			return result, nil
		}
		return nil, err
	} else {
		return nil, model.NewTypeError("wsRowData")
	}
}

func checkRowId(rowId string) bson.M {
	if id, err := primitive.ObjectIDFromHex(rowId); err == nil {
		return bson.M{
			"$or": bson.A{
				bson.M{
					"rowId": id,
				},
				bson.M{
					"rowId": rowId,
				},
			},
		}
	} else {
		return bson.M{
			"rowId": rowId,
		}
	}
}
